#include "timedate.h"
#include "stm32f10x_rtc.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_bkp.h"
#include "stm32f10x_pwr.h"
#include <stdio.h>

/* 每月天数表 (平年) */
static const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

/* 判断是否为闰年 */
static uint8_t Is_Leap_Year(uint16_t year)
{
    return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
}

/* 获取某月的天数 */
static uint8_t Get_Days_In_Month(uint16_t year, uint8_t month)
{
    if (month == 2 && Is_Leap_Year(year))
        return 29;
    else
        return days_in_month[month - 1];
}

/**
  * @brief  RTC配置初始化
  * @param  None
  * @retval None
  */
void RTC_Configuration(void)
{
    /* 使能PWR和BKP时钟 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
    
    /* 允许访问BKP域 */
    PWR_BackupAccessCmd(ENABLE);
    
    /* 检查是否是第一次配置 */
    if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
    {
        /* 备份域复位 */
        BKP_DeInit();
        
#if RTC_CLOCK_SOURCE == RTC_CLOCK_SOURCE_LSE
        /* 使能LSE */
        RCC_LSEConfig(RCC_LSE_ON);
        /* 等待LSE就绪 */
        while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
        /* 选择LSE作为RTC时钟源 */
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
#else
        /* 使能LSI */
        RCC_LSICmd(ENABLE);
        /* 等待LSI就绪 */
        while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
        /* 选择LSI作为RTC时钟源 */
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
#endif
        
        /* 使能RTC时钟 */
        RCC_RTCCLKCmd(ENABLE);
        
        /* 等待RTC寄存器同步 */
        RTC_WaitForSynchro();
        
        /* 等待上次RTC寄存器写操作完成 */
        RTC_WaitForLastTask();
        
        /* 使能RTC秒中断 */
        RTC_ITConfig(RTC_IT_SEC, ENABLE);
        
        /* 等待上次RTC寄存器写操作完成 */
        RTC_WaitForLastTask();
        
#if RTC_CLOCK_SOURCE == RTC_CLOCK_SOURCE_LSE
        /* 设置RTC预分频器: 32767 */
        RTC_SetPrescaler(32767);
#else
        /* 设置RTC预分频器: LSI大约40kHz，设置为39999 */
        RTC_SetPrescaler(39999);
#endif
        
        /* 等待上次RTC寄存器写操作完成 */
        RTC_WaitForLastTask();
        
        /* 设置初始时间为当前时间 */
        RTC_Time_TypeDef init_time = {1970, 1, 1, 0, 0, 0};
        RTC_SetTime(&init_time);
        
        /* 向备份寄存器写入标志 */
        BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
    }
    else
    {
        /* 等待RTC寄存器同步 */
        RTC_WaitForSynchro();
        
        /* 使能RTC秒中断 */
        RTC_ITConfig(RTC_IT_SEC, ENABLE);
        
        /* 等待上次RTC寄存器写操作完成 */
        RTC_WaitForLastTask();
        
        printf("RTC已配置，时间从备份域恢复\r\n");
    }
    
    /* 清除复位标志 */
    RCC_ClearFlag();
    
    /* 配置RTC中断 */
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

/**
  * @brief  将时间结构转换为计数器值
  * @param  time: 时间结构指针
  * @retval 计数器值 (秒数)
  */
uint32_t RTC_Time_To_Counter(RTC_Time_TypeDef *time)
{
    uint32_t counter = 0;
    uint16_t year;
    uint8_t month;
    
    /* 计算年份的秒数 */
    for (year = RTC_BASE_YEAR; year < time->year; year++)
    {
        if (Is_Leap_Year(year))
            counter += 366 * 24 * 3600;  /* 闰年366天 */
        else
            counter += 365 * 24 * 3600;  /* 平年365天 */
    }
    
    /* 计算月份的秒数 */
    for (month = 1; month < time->month; month++)
    {
        counter += Get_Days_In_Month(time->year, month) * 24 * 3600;
    }
    
    /* 计算天数的秒数 */
    counter += (time->day - 1) * 24 * 3600;
    
    /* 计算小时的秒数 */
    counter += time->hour * 3600;
    
    /* 计算分钟的秒数 */
    counter += time->minute * 60;
    
    /* 加上秒数 */
    counter += time->second;
    
    return counter;
}

/**
  * @brief  将计数器值转换为时间结构
  * @param  counter: 计数器值 (秒数)
  * @param  time: 时间结构指针
  * @retval None
  */
void RTC_Counter_To_Time(uint32_t counter, RTC_Time_TypeDef *time)
{
    uint32_t days;
    uint16_t year = RTC_BASE_YEAR;
    uint8_t month = 1;
    
    /* 计算天数 */
    days = counter / (24 * 3600);
    counter %= (24 * 3600);
    
    /* 计算年份 */
    while (days >= (Is_Leap_Year(year) ? 366 : 365))
    {
        if (Is_Leap_Year(year))
            days -= 366;
        else
            days -= 365;
        year++;
    }
    time->year = year;
    
    /* 计算月份 */
    while (days >= Get_Days_In_Month(year, month))
    {
        days -= Get_Days_In_Month(year, month);
        month++;
    }
    time->month = month;
    
    /* 计算日期 */
    time->day = days + 1;
    
    /* 计算小时 */
    time->hour = counter / 3600;
    counter %= 3600;
    
    /* 计算分钟 */
    time->minute = counter / 60;
    
    /* 计算秒 */
    time->second = counter % 60;
}

/**
  * @brief  设置RTC时间
  * @param  time: 时间结构指针
  * @retval None
  */
void RTC_SetTime(RTC_Time_TypeDef *time)
{
    uint32_t counter;
    
    /* 转换为计数器值 */
    counter = RTC_Time_To_Counter(time);
    
    /* 等待上次RTC寄存器写操作完成 */
    RTC_WaitForLastTask();
    
    /* 设置RTC计数器值 */
    RTC_SetCounter(counter);
    
    /* 等待上次RTC寄存器写操作完成 */
    RTC_WaitForLastTask();
}

/**
  * @brief  获取RTC时间
  * @param  time: 时间结构指针
  * @retval None
  */
void RTC_GetTime(RTC_Time_TypeDef *time)
{
    uint32_t counter;
    
    /* 获取RTC计数器值 */
    counter = RTC_GetCounter();
    
    /* 转换为时间结构 */
    RTC_Counter_To_Time(counter, time);
}

/**
  * @brief  生成时间戳字符串
  * @param  timestamp_str: 输出的时间戳字符串缓冲区 (至少20字节)
  * @retval None
  */
void RTC_Generate_Timestamp_String(char *timestamp_str)
{
    RTC_Time_TypeDef current_time;
    
    if (timestamp_str == NULL) return;
    
    /* 获取当前时间 */
    RTC_GetTime(&current_time);
    
    /* 格式化时间字符串 */
    sprintf(timestamp_str, "%04d-%02d-%02d %02d:%02d:%02d", 
            current_time.year, current_time.month, current_time.day,
            current_time.hour, current_time.minute, current_time.second);
}

/**
  * @brief  RTC中断服务函数
  * @param  None
  * @retval None
  */
void RTC_IRQHandler(void)
{
    if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
    {
        /* 清除RTC秒中断标志 */
        RTC_ClearITPendingBit(RTC_IT_SEC);
        
        /* 这里可以添加每秒执行的代码 */
        /* 例如：更新显示、检查闹钟等 */
    }
}
